#pragma once
#include "DesignExtractor.h"
#include <time.h>

//// Public funcs
DesignExtractor::DesignExtractor(){
}

DesignExtractor::DesignExtractor(PKB* p){
	pkb = p;
	next = Next();
	contains = (*p).getContains();
	computeContainsStar();
	computeNext();
	computeNextMatrix();
	computeStmtTable();
	computeFollowsStar();
	computeParentStar();
	computeModifiesTable();
	computeModifiesMap();
	computeUsesTable();
	computeUsesMatrix();
	computeCallsStarList();
	computeAffectBipText();
	computeNextBip();
	computeNextBipMatrix();
}

void DesignExtractor::computeFollowsStar(){
	vector<vector<int>>	matrix((*pkb).getFollowsMatrix());
	vector<pair<int, int>> list((*pkb).getFollowsList());
	StmtTable stmtTable = (*pkb).getStmtTable();
	int totalLineNum = (*pkb).getTotalLineNum();
	
	for(int i=1;i<=totalLineNum;i++){
		for(int j=1;j<=totalLineNum;j++)
			if(matrix.at(i).at(j) == 0 && stmtTable.getLineDetails(i).procNum == stmtTable.getLineDetails(j).procNum)
				for(int k=1;k<=totalLineNum;k++)
					if(matrix.at(i).at(k) == 1 && matrix.at(k).at(j) == 1){
						if(matrix.at(i).at(j) == 0)
							list.push_back(pair<int, int>(i, j));
						matrix.at(i).at(j) = 1;
					}
	}

	(*pkb).setFollowsStarList(list);
	(*pkb).setFollowsStarMatrix(matrix);
}

void DesignExtractor::computeParentStar(){
	vector<vector<int>>	matrix((*pkb).getParentMatrix());
	vector<pair<int, int>> list((*pkb).getParentList());
	StmtTable stmtTable = (*pkb).getStmtTable();
	int totalLineNum = (*pkb).getTotalLineNum();

	for(int i=1;i<=totalLineNum;i++){
		for(int j=1;j<=totalLineNum;j++)
			if(matrix.at(i).at(j) == 0 && stmtTable.getLineDetails(i).procNum == stmtTable.getLineDetails(j).procNum)
				for(int k=1;k<=totalLineNum;k++)
					if(matrix.at(i).at(k) == 1 && matrix.at(k).at(j) == 1){
						if(matrix.at(i).at(j) == 0)
							list.push_back(pair<int, int>(i, j));
						matrix.at(i).at(j) = 1;
					}
	}

	(*pkb).setParentStarList(list);
	(*pkb).setParentStarMatrix(matrix);
}

void DesignExtractor::computeModifiesTable(){
	vector<vector<pair<int,int>>> PTable;
	vector<Triple> ModifiesTable = (*pkb).getModifies().getModifies();
	vector<Triple> CallsTable = (*pkb).getCalls().getCalls();
	vector<Triple> LoopTable = (*pkb).getLoops().getLoops();

	if(ModifiesTable.size()>0){
		int numOfP = (*pkb).getProcTable().getSize();
		for(int i=0;i<numOfP;i++){
			PTable.push_back(vector<pair<int,int>>());
		}
	
		for(int i=0;i<ModifiesTable.size();i++){
			PTable.at(ModifiesTable.at(i).getSecond()).push_back(pair<int,int>(ModifiesTable.at(i).getFirst(),ModifiesTable.at(i).getThird()));
		}

		vector<PTree> PMTable;
		for(int i=0;i<numOfP;i++){		
			PMTable.push_back(PTree());
			PMTable.at(i).setName(i);
			for(int j=0;j<CallsTable.size();j++){
				if(CallsTable.at(j).getSecond()==i){
					PMTable.at(i).children.push_back(CallsTable.at(j).getThird());
					PMTable.at(i).ChildrenAtLine.push_back(CallsTable.at(j).getFirst());
				}
				/*
				if(CallsTable.at(j).getSecond()>i){
					break;
				}
				*/
			}	
		}
	
		for(int i=0;i<numOfP;i++){
			if(PMTable.at(i).children.empty()){
				PMTable.at(i).setFlag(true);
			}
		}

		vector<int> unDoneP;
		for(int i=0;i<numOfP;i++){
			unDoneP.push_back(i);
		}
		while(unDoneP.size()>0){
			for(int j=0;j<unDoneP.size();j++){        // unDoneP.at(j) : undone procedure num
				if(checkChildrenDoneModifies(unDoneP.at(j),PMTable)==true){
					if(PMTable.at(unDoneP.at(j)).children.empty()==false){
						for(int k=0;k<PMTable.at(unDoneP.at(j)).children.size();k++){					
							vector<int> Dupl;					
							for(int l=0;l<PTable.at(PMTable.at(unDoneP.at(j)).children.at(k)).size();l++){							
								bool flagNonDupl = true;					
								for(int d=0;d<Dupl.size();d++){								
									if(Dupl.at(d)==PTable.at(PMTable.at(unDoneP.at(j)).children.at(k)).at(l).second){
										flagNonDupl =false;
										break;
									}
								}
							
								if(flagNonDupl==true){
									PTable.at(unDoneP.at(j)).push_back(pair<int,int>(PMTable.at(unDoneP.at(j)).ChildrenAtLine.at(k),PTable.at(PMTable.at(unDoneP.at(j)).children.at(k)).at(l).second));							
									Dupl.push_back(PTable.at(PMTable.at(unDoneP.at(j)).children.at(k)).at(l).second);
								}
							}					
						}
					}
					PMTable.at(unDoneP.at(j)).setFlag(true);
				    vector <int>::iterator iter;
				    for(iter=unDoneP.begin();iter!=unDoneP.end();++iter){
						if(*iter==unDoneP.at(j)){
						    unDoneP.erase(iter);
						    break;
						}
					}
					break;
				}			
			}
		}
	
	//deal with calls in a loop
		for(int i=0;i<LoopTable.size();i++){
		    vector<int> LoopDupl;		
			for(int j=0;j<PTable.at(LoopTable.at(i).getSecond()).size();j++){
				bool inDuplFlag = false;
			    for(int k=0;k<LoopDupl.size();k++){
					if((LoopTable.at(i).getFirst()==PTable.at(LoopTable.at(i).getSecond()).at(j).first)&&(LoopDupl.at(k)==PTable.at(LoopTable.at(i).getSecond()).at(j).second)){
					    inDuplFlag = true;
					    break;
				    }
				}
				if ((LoopTable.at(i).getFirst()==PTable.at(LoopTable.at(i).getSecond()).at(j).first)&&(inDuplFlag == false)){
				    LoopDupl.push_back(PTable.at(LoopTable.at(i).getSecond()).at(j).second);
			    }
		    }
			for(int l=0;l<PTable.at(LoopTable.at(i).getThird()).size();l++){
			    bool AddedFlag = false;
			    for(int m=0;m<LoopDupl.size();m++){
				    if(PTable.at(LoopTable.at(i).getThird()).at(l).second==LoopDupl.at(m)){
					    AddedFlag = true;
					    break;
				    }
				}
				if(AddedFlag == false){
				    PTable.at(LoopTable.at(i).getSecond()).push_back(pair<int,int>(LoopTable.at(i).getFirst(),PTable.at(LoopTable.at(i).getThird()).at(l).second));
				    LoopDupl.push_back(PTable.at(LoopTable.at(i).getThird()).at(l).second);
			    }
		    }
		}
		vector<pair<int,int>> forFullMT;
		vector<vector<int>> forMTv1;
		vector<pair<int,int>> forMTv2;
		for(int y=0;y<numOfP;y++){
			forMTv1.push_back(vector<int>());
		}

		for(int sum1 = 0;sum1<PTable.size();sum1++){
			for(int sum2 =0;sum2<PTable.at(sum1).size();sum2++){
				forFullMT.push_back(pair<int,int>(PTable.at(sum1).at(sum2).first,PTable.at(sum1).at(sum2).second));
				forMTv1.at(sum1).push_back(PTable.at(sum1).at(sum2).second);
				forMTv2.push_back(pair<int,int>(sum1,PTable.at(sum1).at(sum2).second));
			}
		}
		(*pkb).setFullModifiesTable(forFullMT);
		(*pkb).setPModifiesTableV1(forMTv1);
		(*pkb).setPModifiesTableV2(forMTv2);

	}else {
		(*pkb).setFullModifiesTable(vector<pair<int,int>>());
		(*pkb).setPModifiesTableV1(vector<vector<int>>());
		(*pkb).setPModifiesTableV2(vector<pair<int,int>>());
	}
}

void DesignExtractor::computeModifiesMap(){
	vector<pair<int, int>> modifiesTable = (*pkb).getFullModifiesTable();
	int totalLineNum  = (*pkb).getTotalLineNum();
	vector<int> map = vector<int>(totalLineNum+1, -1);

	for(int i=0;i<modifiesTable.size();i++)
		map.at(modifiesTable.at(i).first) = modifiesTable.at(i).second;
	(*pkb).setFullModifiesMap(map);
}

bool  DesignExtractor::checkChildrenDoneModifies(int n,vector<PTree> PMTable){
	//base case
	if(PMTable.at(n).children.empty()){
		return true;
	}
	//rec
	bool flag = true;
	for(int i=0;i<PMTable.at(n).children.size();i++){
		if (PMTable.at(PMTable.at(n).children.at(i)).getFlag()==false){
			flag =false;
			break;
		}
	}
	return flag;
}

void DesignExtractor::computeUsesTable(){
	vector<vector<pair<int,int>>> PTable;
	vector<Triple> UsesTable = (*pkb).getUses().getUses();
	vector<Triple> CallsTable = (*pkb).getCalls().getCalls();

	if(UsesTable.size()>0){
		int numOfP = (*pkb).getProcTable().getSize();
		for(int i=0;i<numOfP;i++){
			PTable.push_back(vector<pair<int,int>>());
		}
		for(int i=0;i<UsesTable.size();i++){
			PTable.at(UsesTable.at(i).getSecond()).push_back(pair<int,int>(UsesTable.at(i).getFirst(),(*pkb).getUses().getUses().at(i).getThird()));
		}
		vector<PTree> PUTable;	
		for(int i=0;i<numOfP;i++){
		    PUTable.push_back(PTree());
		    PUTable.at(i).setName(i);
		    for(int j=0;j< CallsTable.size();j++){
			    if( CallsTable.at(j).getSecond()==i){
				    PUTable.at(i).children.push_back( CallsTable.at(j).getThird());
				    PUTable.at(i).ChildrenAtLine.push_back( CallsTable.at(j).getFirst());
			    }
				/*
			    if( CallsTable.at(j).getSecond()>i){
				    break;
			    }
				*/
		    }
		}
		for(int i=0;i<numOfP;i++){
		    if(PUTable.at(i).children.empty()){
			    PUTable.at(i).setFlag(true);
		    }
	    }

	    vector<int> unDoneP;
	    for(int i=0;i<numOfP;i++){
		    unDoneP.push_back(i);
	    }
	    while(unDoneP.size()>0){
		    for(int j=0;j<unDoneP.size();j++){        // unDoneP.at(j) : undone procedure num
			    if(checkChildrenDoneUses(unDoneP.at(j),PUTable)==true){
				    if(PUTable.at(unDoneP.at(j)).children.empty()==false){
					    for(int k=0;k<PUTable.at(unDoneP.at(j)).children.size();k++){
						    vector<int> Dupl;
						    for(int l=0;l<PTable.at(PUTable.at(unDoneP.at(j)).children.at(k)).size();l++){
							    bool flagNonDupl = true;
							    for(int d=0;d<Dupl.size();d++){
								    if(Dupl.at(d)==PTable.at(PUTable.at(unDoneP.at(j)).children.at(k)).at(l).second){
									    flagNonDupl =false;
									    break;
								    }
							    }
							
							    if(flagNonDupl==true){
							        PTable.at(unDoneP.at(j)).push_back(pair<int,int>(PUTable.at(unDoneP.at(j)).ChildrenAtLine.at(k),PTable.at(PUTable.at(unDoneP.at(j)).children.at(k)).at(l).second));
								    Dupl.push_back(PTable.at(PUTable.at(unDoneP.at(j)).children.at(k)).at(l).second);
							    }
						    }
					    }
				    }
				    PUTable.at(unDoneP.at(j)).setFlag(true);
				    vector <int>::iterator iter;
				    for(iter=unDoneP.begin();iter!=unDoneP.end();++iter){
					    if(*iter==unDoneP.at(j)){
						    unDoneP.erase(iter);
						    break;
					    }
				    }
				    break;
			    }					
			}
	    }
		
	    //deal with calls in a loop
		for(int i=0;i<(*pkb).getLoops().getLoops().size();i++){
		    vector<int> LoopDupl;
		    for(int j=0;j<PTable.at((*pkb).getLoops().getLoops().at(i).getSecond()).size();j++){
			    bool inDuplFlag = false;
			    for(int k=0;k<LoopDupl.size();k++){
				    if(((*pkb).getLoops().getLoops().at(i).getFirst()==PTable.at((*pkb).getLoops().getLoops().at(i).getSecond()).at(j).first)&&(LoopDupl.at(k)==PTable.at((*pkb).getLoops().getLoops().at(i).getSecond()).at(j).second)){
					    inDuplFlag = true;
					    break;
				    }
			    }
			    if (((*pkb).getLoops().getLoops().at(i).getFirst()==PTable.at((*pkb).getLoops().getLoops().at(i).getSecond()).at(j).first)&&(inDuplFlag == false)){
				    LoopDupl.push_back(PTable.at((*pkb).getLoops().getLoops().at(i).getSecond()).at(j).second);
			    }
		    }
		    for(int l=0;l<PTable.at((*pkb).getLoops().getLoops().at(i).getThird()).size();l++){
			    bool AddedFlag = false;
			    for(int m=0;m<LoopDupl.size();m++){
				    if(PTable.at((*pkb).getLoops().getLoops().at(i).getThird()).at(l).second==LoopDupl.at(m)){
					    AddedFlag = true;
					    break;
				    }
			    }
			    if(AddedFlag == false){
				    PTable.at((*pkb).getLoops().getLoops().at(i).getSecond()).push_back(pair<int,int>((*pkb).getLoops().getLoops().at(i).getFirst(),PTable.at((*pkb).getLoops().getLoops().at(i).getThird()).at(l).second));
				    LoopDupl.push_back(PTable.at((*pkb).getLoops().getLoops().at(i).getThird()).at(l).second);
			    }
		    }
	    }

	    vector<pair<int,int>> forFullUT;
		vector<vector<int>> forUTv1;
		vector<pair<int,int>> forUTv2; 
		for(int y=0;y<numOfP;y++){
			forUTv1.push_back(vector<int>());
		}

		for(int sum1 = 0;sum1<PTable.size();sum1++){
			for(int sum2 =0;sum2<PTable.at(sum1).size();sum2++){
				forFullUT.push_back(pair<int,int>(PTable.at(sum1).at(sum2).first,PTable.at(sum1).at(sum2).second));
				forUTv1.at(sum1).push_back(PTable.at(sum1).at(sum2).second);
				forUTv2.push_back(pair<int,int>(sum1,PTable.at(sum1).at(sum2).second));
			}
		}
		(*pkb).setFullUsesTable(forFullUT);
		(*pkb).setPUsesTableV1(forUTv1);
		(*pkb).setPUsesTableV2(forUTv2);
        }else{			
			(*pkb).setFullUsesTable(vector<pair<int,int>>());		
			(*pkb).setPUsesTableV1(vector<vector<int>>());		
			(*pkb).setPUsesTableV2(vector<pair<int,int>>());
	    }
}

void DesignExtractor::computeUsesMatrix(){
	vector<vector<int>> matrix = (*pkb).getFullUsesMatrix();
	vector<pair<int, int>> list = (*pkb).getFullUsesTable();

	for(int i=0;i<list.size();i++)
		matrix.at(list.at(i).first).at(list.at(i).second) = 1;
	(*pkb).setFullUsesMatrix(matrix);
}

bool  DesignExtractor::checkChildrenDoneUses(int n,vector<PTree> PUTable){
	//base case
	if(PUTable.at(n).children.empty()){
		return true;
	}
	//rec
	bool flag = true;
	for(int i=0;i<PUTable.at(n).children.size();i++){
		if (PUTable.at(PUTable.at(n).children.at(i)).getFlag()==false){
			flag =false;
			break;
		}
	}
	return flag;
}

void DesignExtractor::checkASTforNext(TNode* node, int nextLine) {
	int line = (*node).getProcLine();
	if (((*node).getNodeType().compare("Program")==0) ||
		((*node).getNodeType().compare("Procedure")==0) ||
		((*node).getNodeType().compare("Statement")==0)) {
		int n = (*node).getNumOfMoreChild();
		for (int i=0; i<n; i++) {
			TNode* p1 = *((*node).getMoreChildren()+i);
			if (i==n-1) {
				checkASTforNext(p1, -1);
			} else {
				TNode* p2 = *((*node).getMoreChildren()+(i+1));
				int newNextLine = (*p2).getProcLine();
				checkASTforNext(p1, newNextLine);
			}
		}
	} else if (((*node).getNodeType().compare("Assign")==0) ||
		((*node).getNodeType().compare("Call")==0)) {
		next.setNext(line, nextLine);
	} else if ((*node).getNodeType().compare("While")==0) {
		TNode* stmtNode = (*node).getMoreChildren()[1];
		int n = (*stmtNode).getNumOfMoreChild();
		next.setNext(line, (*(*stmtNode).getMoreChildren()[0]).getProcLine());
		for (int i=0; i<n; i++) {
			TNode* p1 = *((*stmtNode).getMoreChildren()+i);
			if (i==n-1) {
				checkASTforNext(p1, line);
			} else {
				TNode* p2 = *((*stmtNode).getMoreChildren()+(i+1));
				int newNextLine = (*p2).getProcLine();
				checkASTforNext(p1, newNextLine);
			}
		}
		next.setNext(line, nextLine);
	} else if ((*node).getNodeType().compare("If")==0) {
		TNode* thenNode = (*node).getMoreChildren()[1];
		int n = (*thenNode).getNumOfMoreChild();
		next.setNext(line, (*(*thenNode).getMoreChildren()[0]).getProcLine());
		for (int i=0; i<n; i++) {
			TNode* p1 = *((*thenNode).getMoreChildren()+i);
			if (i==n-1) {
				checkASTforNext(p1, nextLine);
			} else {
				TNode* p2 = *((*thenNode).getMoreChildren()+(i+1));
				int newNextLine = (*p2).getProcLine();
				checkASTforNext(p1, newNextLine);
			}
		}
		TNode* elseNode = (*node).getMoreChildren()[2];
		int m = (*elseNode).getNumOfMoreChild();
		next.setNext(line, (*(*elseNode).getMoreChildren()[0]).getProcLine());
/*		if (m==1) {
			checkASTforNext((*elseNode).getMoreChildren()[0], -1);
		}	*/
		for (int i=0; i<m; i++) {
			TNode* p1 = *((*elseNode).getMoreChildren()+i);
			if (i==m-1) {
				checkASTforNext(p1, nextLine);
			} else {
				TNode* p2 = *((*elseNode).getMoreChildren()+(i+1));
				int newNextLine = (*p2).getProcLine();
				checkASTforNext(p1, newNextLine);
			}
		}
	}
}

void DesignExtractor::computeNext() {
	AST _ast = (*pkb).getAST();
	TNode* root = _ast.getRoot();
	checkASTforNext(root, -1);
	(*pkb).setNext(next);
}

void DesignExtractor::computeNextMatrix(){
	vector<pair<int, int>> nextList = (*pkb).getNextList();
	int totalLineNum = (*pkb).getTotalLineNum();
	vector<vector<int>> matrix(totalLineNum+1, vector<int>(totalLineNum+1,0));

	for(int i=0;i<nextList.size();i++)
		matrix.at(nextList.at(i).first).at(nextList.at(i).second) = 1;
	(*pkb).setNextMatrix(matrix);
}

void DesignExtractor::computeCallsStarList(){
	ProcTable procTable = (*pkb).getProcTable();
	int procTableSize = procTable.getSize();
	vector<pair<int,int>> callsList = (*pkb).getCallsList(), callsStarList(callsList);
	vector<vector<int>> callStarMatrix(procTableSize, vector<int>(procTableSize, 0));

	for(int i=0;i<callsList.size();i++)
		callStarMatrix.at(callsList.at(i).first).at(callsList.at(i).second) = 1;
	
	for(int i=0;i<procTableSize;i++){
		for(int j=0;j<procTableSize;j++)
			if(callStarMatrix.at(i).at(j) == 0){
				for(int k=0;k<procTableSize;k++)
					if(callStarMatrix.at(i).at(k) == 1 && callStarMatrix.at(k).at(j) == 1){
						callsStarList.push_back(pair<int,int>(i,j));
						callStarMatrix.at(i).at(j) = 1;
					}
			}
	}

	(*pkb).setCallsStarList(callsStarList);
}

int DesignExtractor::getEnd(TNode* node){
	TNode** children = (*node).getMoreChildren();
	int numCh = (*node).getNumOfMoreChild();
	TNode* lastNode = children[numCh-1];
	if((*lastNode).getNodeType() == "Assign" || (*lastNode).getNodeType() == "Call")
		return (*lastNode).getProcLine();

	getEnd(lastNode);
}

void DesignExtractor::computeStmtTable(){
	AST ast = (*pkb).getAST();
	Next next = (*pkb).getNext();
	int totalLineNum = (*pkb).getTotalLineNum();
	vector<stmt_t> stmtTable = vector<stmt_t>(totalLineNum+1);
	vector<while_t> whileTable;
	vector<if_t> ifTable;
	int procNum = 0;
	int whileCounter = 0, ifCounter = 0;

	for(int i=1;i<=totalLineNum;i++){
		TNode* node = ast.getNodeFromLineNum(ast.getRoot(), i);
		if(	(*(*(*node).getParent()).getParent()).getNodeType() == "Procedure" &&
			(*(*(*node).getParent()).getParent()).getIndex() != procNum)
			procNum = (*(*(*node).getParent()).getParent()).getIndex();
		stmt_t line = {i, (*node).getNodeType(), procNum, -1};
		stmtTable.insert(stmtTable.begin()+i, line);

		if((*node).getNodeType() == "While"){
			while_t wNode;
			wNode.lineNum = i;
			wNode.loopStartLine = i+1;
			wNode.loopEndLine = getEnd(ast.getNodeFromLineNum(ast.getRoot(),i));

			whileTable.push_back(wNode);
			stmtTable.at(i).index = whileCounter;
			whileCounter++;
		}
		if((*node).getNodeType() == "If"){
			if_t iNode;
			iNode.lineNum = i;
			iNode.thenStartLine = i+1;
			TNode* node = ast.getNodeFromLineNum(ast.getRoot(), i);
			TNode* elseNode = (*node).getMoreChildren()[2];
			TNode* elseFirst = (*elseNode).getMoreChildren()[0];
			iNode.thenEndLine = (*elseFirst).getProcLine() - 1;
			iNode.elseStartLine = (*elseFirst).getProcLine();
			iNode.elseEndLine = getEnd(ast.getNodeFromLineNum(ast.getRoot(),i));

			ifTable.push_back(iNode);
			stmtTable.at(i).index = ifCounter;
			ifCounter++;
		}
	}

	StmtTable st = StmtTable();
	st.setStmtTable(stmtTable);
	st.setWhileTable(whileTable);
	st.setIfTable(ifTable);
	(*pkb).setStmtTable(st);
}

void DesignExtractor::computeAffectBipText(){
	vector<vector<int>> callOrder;
	vector<Triple> callTable = (*pkb).getCalls().getCalls();
	vector<stmt_t> st = (*pkb).getStmtTable().getStmtTable();
	vector<vector<pair<int,int>>> PTable;
	if(true){
		int numOfP = (*pkb).getProcTable().getSize();
		vector<vector<int>> extendProcedure;
		vector<int> extendRoot; 
		vector<PCall> PCallTable;
		vector<PTree> PMTable;
		//bug may found
		//int PMTPosition=0;
		for(int i=0;i<numOfP;i++){	
			callOrder.push_back(vector<int>());
			PMTable.push_back(PTree());
			PMTable.at(i).setName(i);
			for(int j=0;j< callTable.size();j++){
				if( callTable.at(j).getSecond()==i){
					PMTable.at(i).children.push_back(callTable.at(j).getThird());
					PMTable.at(i).ChildrenAtLine.push_back( callTable.at(j).getFirst());
				}
				/*
				if(callTable.at(j).getSecond()>i){
					PMTPosition = j;
				    break;
				}
				*/
			}	
		}
		for(int i=0;i<numOfP;i++){
			PCallTable.push_back(PCall());
		}
		//int PPosition=0;
		for(int i=0;i<numOfP;i++){
			PCallTable.at(i).setName(i);
			if(PMTable.at(i).children.empty()){
				PCallTable.at(i).setFlag(true);
				for(int d=0;d<st.size();d++){
					if(st.at(d).procNum==i){
						PCallTable.at(i).list.push_back(st.at(d).lineNum);
					}
					/*
					if(st.at(d).procNum>i){
						PPosition =d;
						break;
					}
					*/
				}
			}
		}


		for(int h=0;h<numOfP;h++){
			for(int k=0;k<numOfP;k++){
				if(PCallTable.at(k).getFlag()==false){
					bool allChildDone = true;
					for(int m=0;m<PMTable.at(k).children.size();m++){
						if(PCallTable.at(PMTable.at(k).children.at(m)).getFlag()==false){
							allChildDone =false;
							break;
						}
					}
					if(allChildDone == true){
						for(int n=0;n<st.size();n++){
							if(st.at(n).procNum==k){
								PCallTable.at(k).list.push_back(st.at(n).lineNum);
								if(st.at(n).type.compare("Call")==0){
									
									int callee = 0;
									int q;
									for(q=0;q<callTable.size();q++){
										if(st.at(n).lineNum==callTable.at(q).getFirst()){
											callee = callTable.at(q).getThird();
											break;
										}
									}
									callOrder.at(k).push_back(q);
									for(int sg=0;sg<callOrder.at(callee).size();sg++){
										callOrder.at(k).push_back(callOrder.at(callee).at(sg));
									}
									for(int p=0;p<PCallTable.at(callee).list.size();p++){
										PCallTable.at(k).list.push_back(PCallTable.at(callee).list.at(p));
									}
								}
							}
						}
						PCallTable.at(k).setFlag(true);
						break;
					}
				}
			}
		}
		vector<int> orderOfCall;
		vector<int> checkRoot;
		vector<vector<int>> checkList;
		for(int ss=0;ss<numOfP;ss++){
			checkRoot.push_back(1);
		}
		for(int ss=0;ss<numOfP;ss++){
			for(int tt=0;tt<PMTable.at(ss).children.size();tt++){
				checkRoot.at(PMTable.at(ss).children.at(tt)) =0;
			}
		}
		for(int ss=0;ss<numOfP;ss++){
			if(checkRoot.at(ss)==1){
			    checkList.push_back(PCallTable.at(ss).list);
				for(int hj=0;hj<callOrder.at(ss).size();hj++){
					orderOfCall.push_back(callOrder.at(ss).at(hj));
				}
			}
		}
		(*pkb).setSortedCall(orderOfCall);
		(*pkb).setAffectBipSimpleText(checkList,checkRoot);
	}
}


void DesignExtractor::computeNextBipMatrix(){
	vector<pair<int, int>> nextBipList = (*pkb).getNextBipList();
	int totalLineNum = (*pkb).getTotalLineNum();
	vector<vector<int>> matrix(totalLineNum+1, vector<int>(totalLineNum+1,0));

	for(int i=0;i<nextBipList.size();i++)
		matrix.at(nextBipList.at(i).first).at(nextBipList.at(i).second) = 1;
	(*pkb).setNextBipMatrix(matrix);
}

void DesignExtractor::computeNextBip() {
	AST _ast = (*pkb).getAST();
	TNode* root = _ast.getRoot();
	_pc = (*pkb).getProcTable();
	computeProcTable();
	checkASTforNextBip(root, -1);
	(*pkb).setNextBip(nextBip);
}


INDEX DesignExtractor::computeLastLine(INDEX proc, Calls ct) {
	int line = _pc.getProcEndLine(proc);
	if (ct.isCallStatement(line)) {
		int newProc = ct.getCalleeFromLineNum(line);
		int newline = computeLastLine(newProc, ct);
		_pc.setProEndLine(proc, newline);
		return newline;
	} else {
		return line;
	}
} 

void DesignExtractor::computeProcTable() {
	Calls _ct = (*pkb).getCalls();
	int _size = _pc.getSize();
	for (int i=0; i<_size; i++) {
		computeLastLine(i, _ct);
	}
}


void DesignExtractor::checkASTforNextBip(TNode* node, int nextLine) {
	int line = (*node).getProcLine();
	if (((*node).getNodeType().compare("Program")==0) ||
		((*node).getNodeType().compare("Procedure")==0) ||
		((*node).getNodeType().compare("Statement")==0)) {
		int n = (*node).getNumOfMoreChild();
		for (int i=0; i<n; i++) {
			TNode* p1 = *((*node).getMoreChildren()+i);
			if (i==n-1) {
				checkASTforNextBip(p1, -1);
			} else {
				TNode* p2 = *((*node).getMoreChildren()+(i+1));
				int newNextLine = (*p2).getProcLine();
				checkASTforNextBip(p1, newNextLine);
			}
		}
	} else if ((*node).getNodeType().compare("Assign")==0){
		nextBip.setNextBip(line, nextLine);
	} else if ((*node).getNodeType().compare("Call")==0) {
		int procIndex = (*node).getIndex();
		int startLine = _pc.getProStartLine(procIndex);
		int endLine = _pc.getProcEndLine(procIndex);
		nextBip.setNextBip(line, startLine);
		nextBip.setNextBip(endLine, nextLine);
	} else if ((*node).getNodeType().compare("While")==0) {
		TNode* stmtNode = (*node).getMoreChildren()[1];
		int n = (*stmtNode).getNumOfMoreChild();
		nextBip.setNextBip(line, (*(*stmtNode).getMoreChildren()[0]).getProcLine());
		for (int i=0; i<n; i++) {
			TNode* p1 = *((*stmtNode).getMoreChildren()+i);
			if (i==n-1) {
				checkASTforNextBip(p1, line);
			} else {
				TNode* p2 = *((*stmtNode).getMoreChildren()+(i+1));
				int newNextLine = (*p2).getProcLine();
				checkASTforNextBip(p1, newNextLine);
			}
		}
		nextBip.setNextBip(line, nextLine);
	} else if ((*node).getNodeType().compare("If")==0) {
		TNode* thenNode = (*node).getMoreChildren()[1];
		int n = (*thenNode).getNumOfMoreChild();
		nextBip.setNextBip(line, (*(*thenNode).getMoreChildren()[0]).getProcLine());
		for (int i=0; i<n; i++) {
			TNode* p1 = *((*thenNode).getMoreChildren()+i);
			if (i==n-1) {
				checkASTforNextBip(p1, nextLine);
			} else {
				TNode* p2 = *((*thenNode).getMoreChildren()+(i+1));
				int newNextLine = (*p2).getProcLine();
				checkASTforNextBip(p1, newNextLine);
			}
		}
		TNode* elseNode = (*node).getMoreChildren()[2];
		int m = (*elseNode).getNumOfMoreChild();
		nextBip.setNextBip(line, (*(*elseNode).getMoreChildren()[0]).getProcLine());
		if (m==1) {
			checkASTforNextBip((*elseNode).getMoreChildren()[0], -1);
		}	
		for (int i=0; i<m; i++) {
			TNode* p1 = *((*elseNode).getMoreChildren()+i);
			if (i==m-1) {
				checkASTforNextBip(p1, nextLine);
			} else {
				TNode* p2 = *((*elseNode).getMoreChildren()+(i+1));
				int newNextLine = (*p2).getProcLine();
				checkASTforNextBip(p1, newNextLine);
			}
		}
	}
}

vector<TNode*> DesignExtractor::computeChildStar(TNode* parent) {
	int n = (*parent).getNumOfMoreChild();
	vector<TNode*> result;
	for (int i=0; i<n; i++) {
		TNode* child = *((*parent).getMoreChildren()+i);
		result.push_back(child);
		vector<TNode*> r_child = computeChildStar(child);
		for (int j=0; j<r_child.size(); j++) {
			result.push_back(r_child.at(j));
		}
	}
	string p_nodetype = (*parent).getNodeType();
	if (p_nodetype=="Statement") p_nodetype = "StmtLst";
	for (int i=0; i<result.size(); i++) {
		TNode* child = result.at(i);
		string c_nodetype = (*child).getNodeType();
		if (c_nodetype=="Statement") c_nodetype = "StmtLst";
		contains.insertContainsStar(p_nodetype, (*parent).getIndex(), (*parent).getProcLine(),
			c_nodetype, (*child).getIndex(), (*child).getProcLine());
	}
	return result;
}

void DesignExtractor::computeContainsStar() {
	AST _ast = (*pkb).getAST();
	TNode* root = _ast.getRoot();
	computeChildStar(root);
	(*pkb).setContains(contains);
}
